home *** CD-ROM | disk | FTP | other *** search
/ JCSM Shareware Collection 1993 November / JCSM Shareware Collection - 1993-11.iso / cl760 / garfforj.lzh / GRAPHLIB.FOR < prev    next >
Text File  |  1991-04-08  |  50KB  |  1,273 lines

  1. ****************************************************************************
  2. c
  3. c      SHAREWARE NOTICE              Copyright (C) D.I. Hoyer, 1990/1991.
  4. c     ==================             GRAPHLIB.for  v3.0
  5. c
  6. c     Please register by sending US$35-00 or Aus$40-00 to the address below
  7. c     if you find these Fortran subroutines useful. Registered users will
  8. c     receive the latest version, plus technical support on queries related
  9. c     to these routines.
  10. c
  11. c                    David I Hoyer
  12. c                    P.O. Box 1743
  13. c                    Macquarie Centre NSW 2113
  14. c                    AUSTRALIA
  15. c
  16. c     This subroutine library is a shareware product. Copies of the original
  17. c     unmodified programs and manual on disk may be made and distributed as 
  18. c     required, as long as they are not charged for. You may not modify the 
  19. c     source code or manual except for your personal use. 
  20. c
  21. c     Requirements  :  ANSI Fortran 77, full language.
  22. c
  23. ****************************************************************************
  24. c
  25. c     No responsibility is accepted for any errors in this software, 
  26. c     or for any loss or damage resulting from using it.
  27. c
  28. ****************************************************************************
  29.  
  30.       SUBROUTINE PRTGRF(IOFF,MMAXX,MMAXY,LOHI,IGRAPH)
  31. *
  32. * Print graph IGRAPH on the dot matrix printer.
  33. *
  34. * Set the following character constants after referring to the printer manual:
  35. *
  36. * LSP7 and LSP12 = Set line spacing to 7/72" and 12/72" (1/6") respectively.
  37. * LSP1  = Set line spacing to 1/216"  [or  1/144"]   (for hi-res plotting)
  38. * LSP20 = Set line spacing to 20/216" [or 13/144"]   ( "    "       "    )
  39. * GFXON = Set graphics mode on, with number of dot columns across page
  40. *             Epson, Star NX-10 : <ESC> 'K'...  =  60 dpi (lo-res)
  41. *                                 <ESC> 'L'...  = 120 dpi (hi-res)
  42. *
  43. * LOHI : Two options are available, viz low and high density.
  44. * 1= Low density = 72 dots per inch vertical and 60 horizontal. Each
  45. *                  row of integers is printed as two lines of 7 rows
  46. *                  each on the printer. 8"x10" = 41k. IGRAPH(480,43)
  47. * 2= High   "    = 144 dpi vert and 120 horiz. This is printed in two
  48. *                  interleaved rows, with 1/216" or 1/144" line feed.
  49. *                  8"x10" requires about 164 kbytes : IGRAPH(960,86)
  50. *
  51. * BUT NOTE: Some printers have a basic vertical line spacing of 60 & 180 dpi
  52. * --------  rather than the 72 discussed above. This is indicated if the
  53. *    printer manual refers to vertical line settings as n/60 or n/180 dpi
  54. *    instead of n/72 or n/216. If this is the case, try the following:
  55. *    LSP7  - set line spacing to 7/60"
  56. *    LSP1  - set line spacing to 1/180"
  57. *    LSP20 - set line spacing to 20/180"
  58. * Then make sure your main program calls PREP(... with DPIV = 60.
  59. * (for 60 dots per inch vertical)
  60. *
  61. * If the printer cannot do line feeds of 1/216" to 1/144" then only lo-res
  62. * graphs can be printed.
  63. *
  64. *
  65.       INTEGER*2 IGRAPH
  66.       CHARACTER*5 LSP12
  67.       CHARACTER*4 GFXON
  68.       CHARACTER*3 LSP1,LSP20
  69.       CHARACTER*2 LSP7
  70.       CHARACTER BLANK*100,LINE1*1200,LINE2*1200
  71.       DIMENSION IGRAPH(MMAXX,MMAXY)
  72.       DATA BLANK/'
  73.      $                                              '/
  74. *
  75. * This subroutine is set up for IBM, Epson, Star type dot matrix printers
  76. * which have a smallest line feed of 1/216". Some printers have a smallest
  77. * line feed of 1/144", in which case you should re-define LSP20 to :
  78. *      LSP20 = CHAR(27)//'3'//CHAR(13)
  79. *
  80. * If you have a printer which uses different graphics commands, or if the
  81. * graph doesn't print correctly, consult the printer manual and change
  82. * the appropriate parameters for LSP7, LSP12, LSP1, LSP20, GFXON (and also
  83. * remember to set the CHARACTER*n statements above to the correct sizes):
  84. * LSP7 sometimes gives trouble - if the lo-res plots appear "expanded"
  85. * try   LSP7 = CHAR(27)//'A'//CHAR(7)
  86. *  or   LSP7 = CHAR(27)//'A'//CHAR(7)//CHAR(27)//'2'
  87. * and change CHARACTER*2 LSP7 to   CHARACTER*3 or 5 respectively.
  88. *
  89.       LSP7 = CHAR(27)//'1'
  90.       LSP12 = CHAR(27)//'A'//CHAR(12)//CHAR(27)//'2'
  91.       LSP1 = CHAR(27)//'3'//CHAR(1)
  92.       LSP20 = CHAR(27)//'3'//CHAR(20)
  93. *
  94.       IOFF = MAX(1,IOFF)
  95.       I2 = MMAXX/256
  96.       I1 = MMAXX - 256*I2
  97.       IF(LOHI.EQ.1) THEN
  98. *       Set 60 dots per inch across the page (lo-res)
  99.         GFXON = CHAR(27)//'K'//CHAR(I1)//CHAR(I2)
  100.       ELSE
  101. *       Set 120 dots per inch across the page (hi-res)
  102.         GFXON = CHAR(27)//'L'//CHAR(I1)//CHAR(I2)
  103.       ENDIF
  104.       WRITE(6,303) LSP7
  105.  303  FORMAT(1X,A5)
  106.       DO 10 IROW=MMAXY, 1, -1
  107.         DO 30 ICOL=1, MMAXX
  108.           ICH1 = IGRAPH(ICOL,IROW)/128
  109.           ICH2 = 2*(IGRAPH(ICOL,IROW) - 128*ICH1)
  110.           ICH1 = 2*ICH1
  111.           IF(ICH1.EQ.26) ICH1=18
  112.           IF(ICH2.EQ.26) ICH2=18
  113.           LINE1(ICOL:ICOL) = CHAR(ICH1)
  114.           LINE2(ICOL:ICOL) = CHAR(ICH2)
  115.   30    CONTINUE
  116.         IF(LOHI.EQ.1) THEN
  117.           WRITE(6,101) BLANK(1:IOFF),GFXON,LINE1(1:MMAXX),BLANK(1:IOFF),
  118.      $     GFXON,LINE2(1:MMAXX)
  119.  101      FORMAT(1X,A,A5,A/1X,A,A5,A)
  120.         ELSE
  121.           WRITE(6,404) BLANK(1:IOFF),GFXON,LINE1(1:MMAXX),LSP1
  122.           WRITE(6,404) BLANK(1:IOFF),GFXON,LINE2(1:MMAXX),LSP20
  123.  404      FORMAT(1X,A,A5,A,A3)
  124.         ENDIF 
  125.   10  CONTINUE
  126. * return the printer to 1/6" spacing
  127.       WRITE(6,303) LSP12   
  128.       RETURN
  129.       END
  130.  
  131. *-----------------------------------------------------------------------
  132.  
  133.       SUBROUTINE SETBIT(I,J)
  134. *
  135. * Set bit j in integer i. This method is marginally faster than using
  136. * the IOR function which is available with some Fortran compilers.
  137. *
  138.       INTEGER*2 I
  139.       DIMENSION MASK(0:14)
  140.       DATA MASK/16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1/
  141.       IF(MOD(I,MASK(J-1)).LT.MASK(J)) I = I + MASK(J)
  142.       RETURN
  143.       END
  144.  
  145. *-----------------------------------------------------------------------
  146.  
  147.       SUBROUTINE PREP(XMIN,YMIN,XMAX,YMAX,LOGX,LOGY,LOHI,IVH,
  148.      $ XL,YL,BWLEFT,BWRGHT,BWTOP,BWBOTT,DPIV,DPIH)
  149. *
  150. * Prepare the input data for plotting.
  151. * Calc graph sizes and limits, log conversions etc.
  152. * This subroutine MUST be called before any plotting is done.
  153. *
  154. *  XMIN, XMAX = Min & max x values to define edges of plotting area.
  155. *  YMIN, YMAX = Min & max y values to define edges of plotting area.
  156. *  LOGX, LOGY = 0 to specify log scales on x or y-axes,
  157. *              1 to specify linear scales.
  158. *  LOHI   = 1 for Low resolution plot (about 4 times quicker than Hi-Res),
  159. *           2 for Hi-Res plot.
  160. *  IVH    = 1 for vertical (portrait) graph format,
  161. *           2 for horizontal (landscape) format.
  162. *  XL     = Length of x-axis, cm.
  163. *  YL     = Length of y-axis, cm.
  164. *  BWLEFT = Border width to left of axes, cm.
  165. *  BWRGHT = Border width to right of axes, cm.
  166. *  BWTOP  = Border width above axes, cm.
  167. *  BWBOTT = Border width below axes, cm.
  168. *  DPIH   = Horizontal dots per inch for lo-res plotting (normally 60)
  169. *  DPIV   = Vertical dots per inch for lo-res plotting (normally 72 or 60)
  170. *
  171. *   The border widths allow room outside the graph axes for plotting labels,
  172. *   titles etc. These add to the overall plotting area. Note that the total
  173. *   plotting height and width (including borders) may not exceed the capacity
  174. *   of IGRAPH, otherwise a run-time error will occur. The total plotting
  175. *   area available depends on the dimension of IGRAPH in the main program,
  176. *   and the number of dots per inch for the printer being used.
  177. *
  178.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN2,YMIN2,XMAX2,YMAX2,
  179.      $   MAXX,MAXY,MMAXX,MMAXY,LOHI2,IVH2,LOGX2,LOGY2,DPIV2,DPIH2
  180. *
  181. *  XMINA..YMAXA = Min/max coordinate values of the edges of the plotting area.
  182. *  They are derived from XMIN..YMAX and axis lengths and border widths.
  183. *
  184. * If log scales are specified, then take logs of axis details
  185.       IF(LOGX.EQ.0) THEN
  186.         XMIN = ALOG10(XMIN)
  187.         XMAX = ALOG10(XMAX)
  188.       ENDIF
  189.       IF(LOGY.EQ.0) THEN
  190.         YMIN = ALOG10(YMIN)
  191.         YMAX = ALOG10(YMAX)
  192.       ENDIF
  193. * Allow extra space above, below, left & right, for labels and headings.
  194. * The numbers refers to cm here.
  195.       XMINA = XMIN - BWLEFT/XL*(XMAX-XMIN)
  196.       XMAXA = XMAX + BWRGHT/XL*(XMAX-XMIN)
  197.       YMINA = YMIN - BWBOTT/YL*(YMAX-YMIN)
  198.       YMAXA = YMAX + BWTOP/YL*(YMAX-YMIN)
  199.       IF(IVH.EQ.1) THEN
  200. *------ Vertical format (portrait, or normal)
  201.         WIDTH = XL + BWLEFT + BWRGHT
  202.         HEIGHT = YL + BWTOP + BWBOTT
  203.       ELSE
  204. *------ If horizontal (landscape) format selected, transform width/height
  205.         WIDTH = YL + BWTOP + BWBOTT
  206.         HEIGHT = XL + BWLEFT + BWRGHT
  207.       ENDIF
  208. * Set the number of dots vert. and horiz. for required graph size
  209.       IF(LOHI.EQ.1) THEN
  210.         MAXX = INT(WIDTH*DPIH/2.54+1.5)
  211.         MAXY = INT(HEIGHT*DPIV/2.54+1.5)
  212.       ELSE
  213.         MAXX = INT(WIDTH*2*DPIH/2.54+1.5)
  214.         MAXY = INT(HEIGHT*2*DPIV/2.54+1.5)
  215.       ENDIF
  216.       MMAXX = MAXX
  217.       MMAXY = MAXY/14+1
  218.       IF(IVH.EQ.2) THEN
  219.         I = MAXX
  220.         MAXX = MAXY
  221.         MAXY = I
  222.       ENDIF
  223.       XMIN2 = XMIN
  224.       YMIN2 = YMIN
  225.       XMAX2 = XMAX
  226.       YMAX2 = YMAX
  227.       LOHI2 = LOHI
  228.       IVH2 = IVH
  229.       LOGX2 = LOGX
  230.       LOGY2 = LOGY
  231.       DPIV2 = DPIV
  232.       DPIH2 = DPIH
  233.       RETURN
  234.       END
  235.  
  236. *-----------------------------------------------------------------------
  237.  
  238.       SUBROUTINE CLRBOX(X1,Y1,X2,Y2,LTYP,INOUT,IGRAPH)
  239. *
  240. * Clear a rectangular area of the graph, and draw a box around
  241. * the cleared area as an additional option.
  242. * See also subroutine  LGDBOX(...
  243. *
  244. * NOTE: This sub-program contains the IAND(-,-) statement which is not
  245. *       standard Fortran-77. However, most F77 compilers recognise it.
  246. *       If yours does not recognise it you will have to delete this
  247. *       subroutine, and the reference to it in the main program.
  248. *
  249. * (X1,Y1) = coordinates of top left corner of box to be cleared
  250. * (X2,Y2) = coordinates of bottom right corner of box to be cleared
  251. * LTYP    = Line type for border around box (0=none, 1=solid etc.)
  252. * IGRAPH  = The graph memory array
  253. *
  254. * Useful for clearing an area which may contain grid lines, or
  255. * other data, before drawing a legend table or other text.
  256. *
  257.  
  258.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  259.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  260.       INTEGER*2 IGRAPH
  261.       DIMENSION IGRAPH(MMAXX,MMAXY), MASK1(14), MASK2(14)
  262.       DIMENSION MASKH1(14), MASKH2(14)
  263.       DATA MASK2/16382,16380,16376,16368,16352,16320,16256,16128,
  264.      $           15872,15360,14336,12288,8192,0/
  265.       DATA MASK1/1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383/
  266.       DATA MASKH2/16382,16254,16252,15996,15992,15480,15472,14448,
  267.      $            14432,12384,12352,8256,8192,0/
  268.       DATA MASKH1/1,129,131,387,391,903,911,1935,1951,3999,4031,
  269.      $            8127,8191,16383/
  270.  
  271. * Check boundary restrictions
  272.       IF(INOUT.EQ.0) THEN
  273.         X1 = AMAX0(XMIN,AMIN0(X1,XMAX))
  274.         X2 = AMAX0(XMIN,AMIN0(X2,XMAX))
  275.         Y1 = AMAX0(YMIN,AMIN0(Y1,YMAX))
  276.         Y2 = AMAX0(YMIN,AMIN0(Y2,YMAX))
  277.       ELSE
  278.         X1 = AMAX0(XMINA,AMIN0(X1,XMAXA))
  279.         X2 = AMAX0(XMINA,AMIN0(X2,XMAXA))
  280.         Y1 = AMAX0(YMINA,AMIN0(Y1,YMAXA))
  281.         Y2 = AMAX0(YMINA,AMIN0(Y2,YMAXA))
  282.       ENDIF
  283.  
  284. * Calc integer values of the box coordinates.
  285.       IF(IVH.EQ.1) THEN
  286.         IX1 = INT((X1-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  287.         IY1 = INT((Y1-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  288.         IX2 = INT((X2-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  289.         IY2 = INT((Y2-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  290.       ELSE
  291.         IX1 = MAXY - INT((Y1-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  292.         IY1 = INT((X1-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+0.5)
  293.         IX2 = MAXY - INT((Y2-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  294.         IY2 = INT((X2-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+0.5)
  295.       ENDIF
  296. * Sort ix1, ix2 into order, and sort iy1, iy2 into order
  297.       IF(IX2.LT.IX1) THEN
  298.         I = IX1
  299.         IX1 = IX2
  300.         IX2 = I
  301.       ENDIF
  302.       IF(IY2.LT.IY1) THEN
  303.         I = IY1
  304.         IY1 = IY2
  305.         IY2 = I
  306.       ENDIF
  307. * Prepare for clearing
  308.       JY2 = IY2/14
  309.       JY1 = (IY1-2)/14+2
  310.       JJY2 = IY2 - 14*JY2
  311.       JJY1 = IY1 - 14*(JY1-2)
  312. * For ix1 to ix2 clear whole integers jy1 to jy2
  313.       IF(JY1.LE.JY2) THEN
  314.         DO 10 I=IX1,IX2
  315.           DO 20 J=JY1,JY2
  316.             IGRAPH(I,J) = 0
  317.   20      CONTINUE
  318.   10    CONTINUE
  319.       ENDIF
  320. * For ix1 to ix2 clear partial integer jy2+1
  321.       IF(JY2.LT.MAXY.AND.JJY2.GT.0.AND.JJY2.LT.15) THEN
  322.         IF(LOHI.EQ.1) J = MASK2(JJY2)
  323.         IF(LOHI.EQ.2) J = MASKH2(JJY2)
  324.         DO 30 I=IX1,IX2
  325.           IGRAPH(I,JY2+1) = IAND(IGRAPH(I,JY2+1),J)
  326.   30    CONTINUE
  327.       ENDIF
  328. * For ix1 to ix2 clear partial integer jy1-1
  329.       IF(JY1.GT.1.AND.JJY1.LT.15.AND.JJY1.GT.0) THEN
  330.         IF(LOHI.EQ.1) J = MASK1(JJY1)
  331.         IF(LOHI.EQ.2) J = MASKH1(JJY1)
  332.         DO 40 I=IX1,IX2
  333.           IGRAPH(I,JY1-1) = IAND(IGRAPH(I,JY1-1),J)
  334.   40    CONTINUE
  335.       ENDIF
  336. * Now draw the border
  337.       IF(LTYP.GT.0) THEN
  338.         CALL LINE(LTYP,X1,Y2,X2,Y2,IGRAPH,NPP,0,INOUT)
  339.         CALL LINE(LTYP,X2,Y2,X2,Y1,IGRAPH,NPP,0,INOUT)
  340.         CALL LINE(LTYP,X2,Y1,X1,Y1,IGRAPH,NPP,0,INOUT)
  341.         CALL LINE(LTYP,X1,Y1,X1,Y2,IGRAPH,NPP,0,INOUT)
  342.       ENDIF
  343.       RETURN
  344.       END
  345.  
  346. *-----------------------------------------------------------------------
  347.  
  348.       SUBROUTINE LGDBOX(LGDPOS,LINES,ICHRS,LGDSIZ,LTYP,INOUT,IGRAPH)
  349. *
  350. * Clear a rectangular area of the graph for a legend table, and draw a
  351. * box around the cleared area as an additional option.
  352. * See also subroutine  CLRBOX(...
  353. *
  354. * LGDPOS = Legend table position (1 to 8)
  355. * LINES  = Number of lines (entries) in the legend table
  356. * ICHRS  = Max number of characters for any legend
  357. *             (to determine the width of the legend box)
  358. * LGDSIZ = Size of legend text
  359. * LTYP   = Line type for border around box (0=none, 1=solid etc.)
  360. * INOUT  = 0 to clip at the axis boundary, 1 to allow overlapping the axes
  361. * IGRAPH = The graph memory array
  362. *
  363.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  364.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  365.       INTEGER*2 IGRAPH
  366.       DIMENSION IGRAPH(MMAXX,MMAXY)
  367.       ISIZE = MAX0(1,(LGDSIZ*LOHI+1)/2)
  368.       DX = (XMAXA-XMINA)/FLOAT(MAXX)*FLOAT(ISIZE)
  369.       DY = (YMAXA-YMINA)/FLOAT(MAXY)*FLOAT(ISIZE)
  370.       IF(LGDPOS.LT.1.OR.LGDPOS.GT.8) LGDPOS = 1
  371.       YYY = FLOAT(LINES*13+6)*DY
  372.       Y1 = YMAX - 5*DY
  373.       Y2 = Y1 - YYY
  374.       LGDP = LGDPOS
  375.       IF(LGDPOS.GT.4) THEN
  376.         Y1 = YMIN+5*DY
  377.         Y2 = Y1 + YYY
  378.         LGDP = LGDPOS - 4
  379.       ENDIF
  380.       X1 = XMIN + 3.*DX + FLOAT(LGDP-1)*(XMAX-XMIN)/4.
  381.       X2 = X1 + DX*FLOAT(ICHRS)*6 + 33*DX*FLOAT(LOHI)/FLOAT(ISIZE)
  382.       CALL CLRBOX(X1,Y1,X2,Y2,LTYP,INOUT,IGRAPH)
  383.       RETURN
  384.       END
  385.  
  386. *-----------------------------------------------------------------------
  387.  
  388.       SUBROUTINE AXES(NDIVX,IGRDX1,NSDIVX,IGRDX2,NDPX,XLABEL,
  389.      $                NDIVY,IGRDY1,NSDIVY,IGRDY2,NDPY,YLABEL,IORIYV,
  390.      $           TITLE,ISZVAL,VALPOS,ISZXYL,XLBPOS,YLBPOS,ISZTTL,TTLPOS,
  391.      $           JUSTTL,LGDSIZ,LGDPOS,LGDLNS,LGDCHS,LGDTYP,IGRAPH)
  392. *
  393. * Draw a set of axes on linear or logarithmic scales.
  394. * Size and position of labels and axis values can be specified.
  395. * A cleared box for the legend table can be specified.
  396. *
  397. *  NDIVX  = No. of major divisions along x-axis, with axis values printed
  398. *             (set to 0 for log scales, and divisions are calculated)
  399. *  IGRDX1 = Type of grid lines on major x-axis divisions
  400. *             (0=none, 1=solid, 2=dotted etc)
  401. *  NSDIVX = No. of secondary divisions between each major division on x-axis
  402. *  IGRDX2 = Type of grid lines on minor x-axis divisions (0=none, 1..5)
  403. *  NDPX   = No. of decimal places for x-axis values (ignored for log scales)
  404. *  XLABEL = The label or title of the x-axis
  405. *  NDIVY...YLABEL = As for NDIVX...XLABEL, for y-axis
  406. *  IORIYV = Orientation of y-axis values.
  407. *             (0=numbers parallel to y-axis, 1=perpendicular to y-axis)
  408. *  TITLE  = The graph title
  409. *  ISZVAL = The text size for printing axis values
  410. *  VALPOS = To adjust the distance between axis and centre of axis value.
  411. *             (1=default, <1=closer to axis, >1=further from axis)
  412. *  ISZXYL = The text size for printing x and y-axis labels
  413. *  XLBPOS = To adjust the distance between x-axis and x-axis label.
  414. *             1=default, <1=closer to axis, >1=further from axis.
  415. *  YLBPOS = As for XLBPOS, but for y-axis. eg. If IORIYV=1 and the y-axis
  416. *           values are several characters long, set YLBPOS>1 to shift the
  417. *           label further away from the axis.
  418. *  ISZTTL = The text size for printing the graph title
  419. *  TTLPOS = To adjust the distance between axis and centre of graph title.
  420. *             (>0 = Above top axis, <0 = below bottom axis
  421. *             magnitude: 1=default, <1=closer to axis, >1=further from axis)
  422. *  JUSTTL = Justification of graph title. (-1=left, 0=centre, 1=right)
  423. *  LGDSIZ = Size of text for legend table (for drawing the legend box)
  424. *  LGDPOS = Position of the legend box.
  425. *             (1..4 = top left to top right, 5..8 = bottom left to bottom rt)
  426. *  LGDLNS = Number of lines of text to be allocated for legend box
  427. *             (set to 0 for no legend box)
  428. *  LGDCHS = Max number of characters in a legend text (for the legend box)
  429. *  LGDTYP = Line type for surrounding the legend box (0=none, 1=solid etc)
  430. *  IGRAPH = The graph memory array
  431. *
  432.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  433.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  434.       INTEGER*2 IGRAPH
  435.       CHARACTER*80 TITLE, XLABEL, YLABEL, AXVAL, FMT
  436.       DIMENSION IGRAPH(MMAXX,MMAXY)
  437.       CALL LINE(1,XMIN,YMIN,XMAX,YMIN,IGRAPH,NPP,0,1)
  438.       CALL LINE(1,XMIN,YMIN,XMIN,YMAX,IGRAPH,NPP,0,1)
  439.       CALL LINE(1,XMIN,YMAX,XMAX,YMAX,IGRAPH,NPP,0,1)
  440.       CALL LINE(1,XMAX,YMAX,XMAX,YMIN,IGRAPH,NPP,0,1)
  441. * These are for spacing the labels
  442.       ISIZE1 = MAX0(1,(ISZTTL*LOHI+1)/2)
  443.       ISIZE2 = MAX0(1,(ISZXYL*LOHI+1)/2)
  444.       ISIZE3 = MAX0(1,(ISZVAL*LOHI+1)/2)
  445.       YY1 = 13*ABS(TTLPOS)*(YMAXA-YMINA)/FLOAT(MAXY)*FLOAT(ISIZE1)
  446.       YY2 = 13*ABS(XLBPOS)*(YMAXA-YMINA)/FLOAT(MAXY)*FLOAT(ISIZE2)
  447.       YY3 = 7*ABS(VALPOS)*(YMAXA-YMINA)/FLOAT(MAXY)*FLOAT(ISIZE3)
  448.       XX2 = 13*ABS(YLBPOS)*(XMAXA-XMINA)/FLOAT(MAXX)*FLOAT(ISIZE2)
  449.       XX3 = 7*ABS(VALPOS)*(XMAXA-XMINA)/FLOAT(MAXX)*FLOAT(ISIZE3)
  450. * Plot graph heading
  451.       X = (XMAX+XMIN)/2.
  452.       IF(JUSTTL.LT.0) X = XMIN
  453.       IF(JUSTTL.GT.0) X = XMAX
  454.       IF(TTLPOS.GE.0) Y = YMAX + YY1
  455.       IF(TTLPOS.LT.0) Y = YMIN - YY1 - YY2 - YY3
  456.       CALL TEXT(X,Y,TITLE,1,ISZTTL,JUSTTL,IGRAPH,1)
  457. * Plot x-axis and y-axis labels
  458.       DO 30 IAX=0, 1
  459.         IF(IAX.EQ.0) THEN
  460.           NDIVS = AMAX0(1,NDIVX)
  461.           NSDIVS = AMAX0(1,NSDIVX)
  462.           LOGS = LOGX
  463.           IGRDS1 = IGRDX1
  464.           IGRDS2 = IGRDX2
  465.           AXMIN = XMIN
  466.           AXMAX = XMAX
  467.           Y = YMIN - YY2 - YY3
  468.           X = (XMAX+XMIN)/2.
  469.           CALL TEXT(X,Y,XLABEL,1,ISZXYL,0,IGRAPH,1)
  470.         ELSE
  471.           NDIVS = AMAX0(1,NDIVY)
  472.           NSDIVS = AMAX0(1,NSDIVY)
  473.           LOGS = LOGY
  474.           IGRDS1 = IGRDY1
  475.           IGRDS2 = IGRDY2
  476.           AXMIN = YMIN
  477.           AXMAX = YMAX
  478.           X = XMIN - XX2 - XX3
  479.           Y = (YMAX+YMIN)/2.
  480.           CALL TEXT(X,Y,YLABEL,2,ISZXYL,0,IGRAPH,1)
  481.         ENDIF
  482. * Set size of tick marks along axis
  483.         IF(IAX.EQ.0) AXLL = (YMAXA-YMINA)*3./FLOAT(MAXY-1)
  484.         IF(IAX.EQ.1) AXLL = (XMAXA-XMINA)*3./FLOAT(MAXX-1)
  485.         IF(LOHI.EQ.2) AXLL = 2.*AXLL
  486. * Calc number of major/minor tick marks on axis
  487.         JDIV = NSDIVS
  488.         IF(LOGS.NE.0) THEN
  489. *         Linear axis scale
  490.           I1 = 0
  491.           I2 = NDIVS
  492.         ELSE
  493. *         Log scale
  494.           I1 = INT(AXMIN) - 1
  495.           I2 = INT(AXMAX) + 1
  496.         ENDIF
  497. * Plot tick mark(s) on the axis
  498.         DO 10 I=I1, I2
  499.           DO 20 J = 1, JDIV
  500.             AXL = AXLL
  501.             IF(J.EQ.1) THEN
  502. *             major division
  503.               AXL = AXLL*1.5
  504.               IGRID = IGRDS1
  505.             ELSE
  506. *             minor division
  507.               IGRID = IGRDS2
  508.             ENDIF
  509.             IF(LOGS.NE.0) THEN
  510.               XY = AXMIN+(AXMAX-AXMIN)/FLOAT(NDIVS)*(I+(J-1)/
  511.      $             FLOAT(NSDIVS))
  512.             ELSE
  513.               XY = ALOG10(10.**FLOAT(I)*FLOAT(J))
  514.             ENDIF
  515.             IF(IAX.EQ.0) THEN
  516.               CALL LINE(1,XY,YMAX,XY,YMAX-AXL,IGRAPH,NPP,0,0)
  517.               CALL LINE(1,XY,YMIN,XY,YMIN+AXL,IGRAPH,NPP,0,0)
  518.             ELSE
  519.               CALL LINE(1,XMAX,XY,XMAX-AXL,XY,IGRAPH,NPP,0,0)
  520.               CALL LINE(1,XMIN,XY,XMIN+AXL,XY,IGRAPH,NPP,0,0)
  521.             ENDIF
  522.             IF(IGRID.GT.0) THEN
  523.               NPP = 0
  524.               IF(IAX.EQ.0) CALL LINE(IGRID,XY,YMIN,XY,YMAX,IGRAPH,NPP,0,
  525.      $                               0)
  526.               IF(IAX.EQ.1) CALL LINE(IGRID,XMIN,XY,XMAX,XY,IGRAPH,NPP,0,
  527.      $                               0)
  528.             ENDIF
  529. * Plot the axis value at this position
  530.             IF(J.EQ.1.AND.IAX.EQ.0.AND.XY.GE.XMIN.AND.XY.LE.XMAX) THEN
  531.               IF(LOGS.EQ.0) NDPX = MAX0(0,INT(0.1-XY))
  532.               WRITE(FMT,"('(F20.',I1,')')") NDPX
  533.               WRITE(AXVAL,FMT) XY
  534.               IF(LOGS.EQ.0) WRITE(AXVAL,FMT) 10.**(XY)
  535.               IB = 0
  536.   40          IB = IB + 1
  537.               IF(AXVAL(IB:IB).EQ.' '.OR.AXVAL(IB:IB).EQ.'0') GOTO 40
  538.               IF(IB.GT.1) AXVAL = AXVAL(IB:LENG(AXVAL))
  539.               IF(LENG(AXVAL).EQ.1.AND.AXVAL(1:1).EQ.'.') AXVAL = '0'
  540.               IB = LENG(AXVAL)
  541.               IF(AXVAL(IB:IB).EQ.'.') AXVAL = AXVAL(1:IB-1)
  542.               Y = YMIN - YY3
  543.               X = XY
  544.               CALL TEXT(X,Y,AXVAL,1,ISZVAL,0,IGRAPH,1)
  545.             ELSE IF(J.EQ.1.AND.IAX.EQ.1.AND.XY.GE.YMIN.AND.XY.LE.YMAX)
  546.      $      THEN
  547.               IF(LOGS.EQ.0) NDPY = MAX0(0,INT(0.1-XY))
  548.               WRITE(FMT,"('(F20.',I1,')')") NDPY
  549.               WRITE(AXVAL,FMT) XY
  550.               IF(LOGS.EQ.0) WRITE(AXVAL,FMT) 10.**(XY)
  551.               IB = 0
  552.   50          IB = IB + 1
  553.               IF(AXVAL(IB:IB).EQ.' '.OR.AXVAL(IB:IB).EQ.'0') GOTO 50
  554.               IF(IB.GT.0) AXVAL = AXVAL(IB:LENG(AXVAL))
  555.               IF(LENG(AXVAL).EQ.1.AND.AXVAL(1:1).EQ.'.') AXVAL = '0'
  556.               IB = LENG(AXVAL)
  557.               IF(AXVAL(IB:IB).EQ.'.') AXVAL = AXVAL(1:IB-1)
  558.               X = XMIN - XX3
  559.               Y = XY
  560.               IF(IORIYV.EQ.0) CALL TEXT(X,Y,AXVAL,2,ISZVAL,0,IGRAPH,1)
  561.               IF(IORIYV.NE.0) CALL TEXT(X,Y,AXVAL,1,ISZVAL,1,IGRAPH,1)
  562.             ENDIF
  563.   20      CONTINUE
  564.   10    CONTINUE
  565.   30  CONTINUE
  566.       IF(LGDLNS.GT.0) CALL LGDBOX(LGDPOS,LGDLNS,LGDCHS,LGDSIZ,
  567.      $                            LGDTYP,1,IGRAPH)
  568.       RETURN
  569.       END
  570.  
  571. *-----------------------------------------------------------------------
  572.  
  573.       SUBROUTINE PLOTD(NPTS,LTYP,MARK,MSIZE,LEGEND,IORI,ITXSIZ,
  574.      $  JUSTIF,INOUT,IGRAPH,STRNG,IFN,P,X,Y,ILEGND,LGDPOS,LGDSIZ)
  575. *
  576. * Plot the data for this curve, or this data set. This subroutine is not
  577. * essential, but gives easy access to most of the plotting functions.
  578. * Note that only some of the input parameters are used on each call,
  579. * depending on the value of NPTS.
  580. *
  581. *   NPTS  = No of data points for current data set, or..
  582. *           0 to plot a function curve,
  583. *           -1 for plotting a text string,
  584. *           -2 to clear a rectangular area of the graph, with optional border.
  585. *   LTYP  = Line type for joining points.
  586. *           0 = no line, 1 to 5 straight lines,
  587. *           -5 to -1 for cubic spline fit (smooth curve) in line type 1..5.
  588. *   MARK  = Symbol to be plotted at each point
  589. *           (1 = dot, 2..8 = symbol, 32..126 = ASCII character)
  590. *   MSIZE = Size of MARK (1..n) Try 3 for a start.
  591. *   LEGEND= Text to describe each data set. Blank to suppress.
  592. *   IORI  = Orientation for plotting a text string (if NPTS=-1).
  593. *           1 = Normal (vertical), 2 = 90 deg anti-clockwise
  594. *           3 = Upside down,       4 = 90 deg clockwise
  595. *   ITXSIZ= Size of text to be plotted (1 to n).  2 = "normal".
  596. *   JUSTIF= Text justification. -1=left, 0=centre, 1=right.
  597. *   INOUT = Border restriction. 0=plot only inside axes, 1=anywhere on graph
  598. *   IGRAPH= The graph memory array
  599. *   STRNG = A string of text to be printed on the graph
  600. *   IFN   = Function number (pre-compiled in FUNCT) to plot if NPTS=0.
  601. *   P     = The array of parameters to be passed to function IFN.
  602. *   X,Y   = The array of points to be plotted (when NPTS>0).
  603. *           Also used for specifying coordinate values for plotting text,
  604. *           box and function plots. ie. when NPTS =...
  605. *                -2 : (x1,y1) and (x2,y2) are the box coordinates
  606. *                -1 : place text at (x1,y1)
  607. *                 0 : plot function from x1 to x2.
  608. *   ILEGND= The legend number in the legend table. Updated automatically
  609. *           whenever another entry is printed in the table.
  610. *   LGDPOS= Position of the legend box.
  611. *           1..4 = top left to top right, 5..8 = bottom left to bottom right.
  612. *           Should be the same as the value used in subroutine AXES(..
  613. *   LGDSIZ= Size of text for legend table (for drawing the legend box)
  614. *
  615. * First plot the legend for this data set, if required
  616. *
  617.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  618.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  619.       INTEGER*2 IGRAPH
  620.       CHARACTER*80 LEGEND, STRNG
  621.       DIMENSION IGRAPH(MMAXX,MMAXY), X(*), Y(*), P(*)
  622. * Write the legend into the legend table
  623.       IF(NPTS.GE.0.AND.(LENG(LEGEND).GT.1.OR.LEGEND(1:1).NE.' ')) THEN
  624.         ISIZE = MAX0(1,(LGDSIZ*LOHI+1)/2)
  625.         DY = (YMAXA-YMINA)/FLOAT(MAXY)*FLOAT(ISIZE)
  626.         ILEGND = ILEGND + 1
  627.         YY = YMAX - 13*DY*FLOAT(ILEGND)
  628.         IF(LGDPOS.LT.1.OR.LGDPOS.GT.8) LGDPOS = 1
  629.         LGDP = LGDPOS
  630.         IF(LGDPOS.GT.4) LGDP = LGDPOS - 4
  631.         IF(LGDPOS.GT.4) YY = YMIN + 13*DY*FLOAT(ILEGND)
  632.         DX = (XMAXA-XMINA)/FLOAT(MAXX)*FLOAT(LOHI)
  633.         XX = XMIN + 18.*DX + FLOAT(LGDP-1)*(XMAX-XMIN)/4.
  634.         CALL MARKPT(MARK,MSIZE,XX,YY,IGRAPH,1)
  635.         XX1 = XX - 13.*DX
  636.         XX2 = XX + 13.*DX
  637.         NPP = 0
  638.         IF(LTYP.NE.0) CALL LINE(IABS(LTYP),XX1,YY,XX2,YY,IGRAPH,NPP,0,1)
  639.         XX = XX + 19.*DX
  640.         CALL TEXT(XX,YY,LEGEND,1,LGDSIZ,-1,IGRAPH,1)
  641.       ENDIF
  642. * If NPTS=-2 then clear a rectangular graph area (x1,y1) to (x2,y2)
  643.       IF(NPTS.EQ.-2) THEN
  644.         IF(LOGX.EQ.0) THEN
  645.           X(1) = ALOG10(X(1))
  646.           X(2) = ALOG10(X(2))
  647.         ENDIF
  648.         IF(LOGY.EQ.0) THEN
  649.           Y(1) = ALOG10(Y(1))
  650.           Y(2) = ALOG10(Y(2))
  651.         ENDIF
  652.         CALL CLRBOX(X(1),Y(1),X(2),Y(2),LTYP,INOUT,IGRAPH)
  653. * If NPTS=-1 then text is to be plotted at (x,y) coordinates.
  654.       ELSEIF(NPTS.EQ.-1) THEN
  655.         IF(LOGX.EQ.0) X(1) = ALOG10(X(1))
  656.         IF(LOGY.EQ.0) Y(1) = ALOG10(Y(1))
  657.         CALL TEXT(X(1),Y(1),STRNG,IORI,ITXSIZ,JUSTIF,IGRAPH,INOUT)
  658. * If NPTS=0 then a function plot is required.
  659.       ELSEIF(NPTS.EQ.0) THEN
  660.         IF(LOGX.EQ.0) THEN
  661. *-------- Log scale on x-axis, so take logs of X1, X2
  662.           X(1) = ALOG10(X(1))
  663.           X(2) = ALOG10(X(2))
  664.         ENDIF
  665.         CALL FUNCT(IFN,P,LTYP,X(1),X(2),IGRAPH,INOUT)
  666. * Else plot the set of points
  667.       ELSEIF(NPTS.GT.0) THEN
  668.         IF(LOGX.EQ.0) THEN
  669. *-------- Log scale for x-axis, so take logs of x values
  670.           DO 20 J=1, NPTS
  671.             X(J) = ALOG10(X(J))
  672.   20      CONTINUE
  673.         ENDIF
  674.         IF(LOGY.EQ.0) THEN
  675. *-------- Log scale for y-axis...
  676.           DO 30 J=1, NPTS
  677.             Y(J) = ALOG10(Y(J))
  678.   30      CONTINUE
  679.         ENDIF
  680. *------ Plot the points
  681.         CALL POINTS(MARK,MSIZE,LTYP,NPTS,X,Y,IGRAPH,INOUT)
  682.       ENDIF
  683.       RETURN
  684.       END
  685.  
  686. *-----------------------------------------------------------------------
  687.  
  688.       SUBROUTINE POINT(XX,YY,IGRAPH,INOUT)
  689. *
  690. * Plot a single point at the coordinate (XX,YY) on IGRAPH
  691. *
  692. * INOUT = 0 to plot the point only if it is inside the axes
  693. *         1 to plot the point anywhere on the page
  694. *
  695. * Each integer in the array IGRAPH has 16 bits, and each bit which
  696. * equals 1 is to be printed as a dot.  However, only 14 are used
  697. * for various technical reasons. In other words the integer at
  698. * IGRAPH(5,2) would contain 14 dot positions corresponding to column
  699. * 5 and rows 17 to 32 of the graph to be printed on the dot matrix
  700. * printer.  MASKHI converts for Hi-res 144 dpi vertical printing, in
  701. * which the row is printed as two interleaved rows 1/144" apart.
  702. *
  703.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  704.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  705.       INTEGER*2 IGRAPH
  706.       DIMENSION IGRAPH(MMAXX,MMAXY), MASKHI(14)
  707.       DATA MASKHI/1,8,2,9,3,10,4,11,5,12,6,13,7,14/
  708.       X = XX
  709.       Y = YY
  710.       IF(INOUT.EQ.0) THEN
  711. * clip at axis boundary
  712.         X = AMAX1(XMIN,AMIN1(XMAX,X))
  713.         Y = AMAX1(YMIN,AMIN1(YMAX,Y))
  714.       ELSE
  715.         X = AMAX1(XMINA,AMIN1(XMAXA,X))
  716.         Y = AMAX1(YMINA,AMIN1(YMAXA,Y))
  717.       ENDIF
  718.       IF(IVH.EQ.1) THEN
  719. *------ Vertical format (normal)
  720.         ICOL = INT((X-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  721.         IY = INT((Y-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  722.       ELSE
  723. *------ If horizontal format selected, then transform values
  724.         ICOL = MAXY - INT((Y-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  725.         IY = INT((X-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+0.5)
  726.       ENDIF
  727.       IROW = IY/14+1
  728.       IBIT = IROW*14-IY
  729.       IF(LOHI.EQ.2) IBIT = MASKHI(IBIT)
  730.       CALL SETBIT(IGRAPH(ICOL,IROW),IBIT)
  731.       RETURN
  732.       END
  733.  
  734. *-----------------------------------------------------------------------
  735.  
  736.       SUBROUTINE MARKPT(IPT,ISIZE,X,Y,IGRAPH,INOUT)
  737. *
  738. * Plot a mark (symbol) of size ISIZE, centred at the point (X,Y) on IGRAPH.
  739. * The symbol shapes are stored as characters, and accessed from TEXT,
  740. * so changes to TEXT may alter these definitions.
  741. *
  742. *  ISIZE = Size of the mark to be plotted (1..n)
  743. *   IPT  =  1 : point
  744. *           2 : open octagon
  745. *           3 : filled  "
  746. *           4 : open square
  747. *           5 : filled  "
  748. *           6 : open triangle
  749. *           7 : filled  "
  750. *           8 : cross
  751. *           9 : plus
  752. *          10 : star
  753. *          11 : open diamond
  754. *          12 : filled  "
  755. *      13-31  : Might be used later. Blank for now.
  756. *      32-126 : plot the corresponding ASCII character (Orientation = 1)
  757. *
  758.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  759.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  760.       INTEGER*2 IGRAPH
  761.       CHARACTER*80 CH, BLNK
  762.       DIMENSION IGRAPH(MMAXX,MMAXY)
  763.       DATA BLNK /' '/
  764.       CH = BLNK
  765.       CALL POINT(X,Y,IGRAPH,INOUT)
  766.       IORI = 1
  767.       IF(IPT.GT.1.AND.IPT.LE.126) THEN 
  768.         CH(1:1) = CHAR(IPT)
  769.         CALL TEXT(X,Y,CH,IORI,ISIZE,0,IGRAPH,INOUT)
  770.       ENDIF
  771.       IF(IPT.EQ.10) THEN
  772.         CH(1:1) = CHAR(8)
  773.         CALL TEXT(X,Y,CH,IORI,ISIZE,0,IGRAPH,INOUT)
  774.       ENDIF
  775.       RETURN
  776.       END
  777.  
  778. *-----------------------------------------------------------------------
  779.  
  780.       SUBROUTINE TEXT(X,Y,STRNG,IORI,ITXSIZ,JUSTIF,IGRAPH,INOUT)
  781. *
  782. * Plot a string of text. Also used to plot graph symbols, using character
  783. * positions 1 to 31 in the ASCII sequence to define these symbols.
  784. *
  785. * (X,Y) = Graph coordinates of the centre of the justification character
  786. *            (actually the centre of upper case characters)
  787. * STRNG = The character string to be plotted
  788. * IORI  = Orientation. 1 = Normal (vertical)
  789. *                      2 = Rotated 90 deg anti-clockwise
  790. *                      3 = Upside down
  791. *                      4 = Rotated 90 deg clockwise
  792. * ITXSIZ= Text size, 1 to n. (Steps of two for lo-res : 2, 4, 6, ...)
  793. * JUSTIF= Justification. -1=Left justified, 0=centre, 1=right.
  794. *                     Y---->   abcde          abcde    abcde
  795. *                     X---->   ^                ^          ^
  796. * IGRAPH= The graph memory array
  797. * INOUT = Border restriction. 0=plot only inside axes, 1=anywhere on graph
  798. *
  799.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  800.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  801.       INTEGER*2 IGRAPH, ICH, NB, NI, CHARS
  802.       CHARACTER*80 STRNG
  803.       CHARACTER CH
  804.       DIMENSION IGRAPH(MMAXX,MMAXY), CHARS(3,126), MASK2(16),
  805.      $ IDOTS(10,0:6)
  806.       DATA MASK2/1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,
  807.      $           32768/
  808.       DATA CHARS/    0,    0,    0, 4208, 1090, 7185,28784, 1987, 7199,
  809.      $            4344, 1090,15889,
  810.      $           28920, 1987,15903, 8240, 1153, 3082,24624, 1921, 3086,
  811.      $            8328,  257, 8714,16416, 1984, 2052,16416, 1984, 2052,
  812.      $            8224, 1089, 2058,24608, 1985, 2062,    0,    0,    0,
  813.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  814.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  815.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  816.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  817.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  818.      $               0,    0,    0,    0,    0,    0,    0,    0,    0,
  819.      $               0,    0,    0,    0, 4000,    0,    0,    7,   56,
  820.      $           30800,17031, 5183,20552, 4066, 9237, 8584,16646, 8969,
  821.      $           18648, 2724, 1297,    0, 3077,    0,    0,18368,   32,
  822.      $            2048, 1988,    0,24648, 2016, 4614,16416, 1984, 2052,
  823.      $            6656,  112,    0,16416,  256, 2052, 6144,   96,    0,
  824.      $            8200,  256, 8200, 2296,18468,15904, 2048,20450,    0,
  825.      $            6276,18596,12580,18692,19236,17972, 8240,17537, 1087,
  826.      $            2504,18981,20008,18552,18722, 1572,  256, 2532,24616,
  827.      $           18648,18724,13860,18624, 2340,15397,22528,  865,    0,
  828.      $           23040,  881,    0, 8224,17473,   32, 8272,  641, 5130,
  829.      $            2048, 1092, 2058,  128, 2212,12324, 2296,19364,15658,
  830.      $            8316, 2178, 7954,30980,18727,13860, 2296,18468, 8736,
  831.      $           30980,18471,15904,18940,18724,16676,16892, 2308,16420,
  832.      $            2296,18468,20004,16892,  256,32516, 2048,20452,   32,
  833.      $            2056, 2080,16447,16892,  640,16657, 2556,16416,  256,
  834.      $             508,  770,32528,  508,  514,32516, 2296,18468,15904,
  835.      $           16892, 2308,12324, 2296,18596,16161,16892, 2436,12581,
  836.      $           18632,18724, 9764,  256, 4068,16416, 2552,16416,32256,
  837.      $            4592,   32,31745, 2552,16832,32256, 8588,  257,25354,
  838.      $             384,  481,24584,10508,18724,24872,30720,18471,   32,
  839.      $             128,  257,  514, 2048,18468,   63,   64, 2050, 4112,
  840.      $             513, 4104,   64,    0, 3072,   40,10248,17057, 3850,
  841.      $            2556,16929, 3592, 2104,16929, 4360, 2104,16929,32520,
  842.      $           10296,17057, 3338,30752, 2307,   36, 2617,21033, 8072,
  843.      $             508,  513, 3848, 2048,19425,    0,  513,25096,   47,
  844.      $            8700,  384,  265, 2048,20452,    0,   60,  481, 3848,
  845.      $             124,  513, 3848, 2104,16929, 3592, 2175,16929, 3592,
  846.      $            2104,16929, 8136,16508,  512, 4104,10276,17057, 4618,
  847.      $           28736,16935,  520, 2168,16416, 7936, 4208,   32, 7169,
  848.      $            2168,16576, 7680,20548,  128, 4357, 2680,20520, 8064,
  849.      $            6212,17057, 4364,16384,18112,16672,    0, 3808,    0,
  850.      $            2308, 1732,    4,  128, 1028, 8200/
  851.       ISIZE = MAX0(1,(ITXSIZ*LOHI+1)/2)
  852.       IF(IORI.LT.1.OR.IORI.GT.4) IORI = 1
  853. * Calc integer value of (X,Y), by analogy with POINT.
  854. * First calc integer limits of plotting area
  855.       IF(IVH.EQ.1) THEN
  856.         IF(INOUT.EQ.0) THEN
  857.           IMINX = INT((XMIN-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  858.           IMAXX = INT((XMAX-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  859.           IMINY = INT((YMIN-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  860.           IMAXY = INT((YMAX-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  861.         ELSE
  862.           IMINX = 0
  863.           IMAXX = MAXX
  864.           IMINY = 0
  865.           IMAXY = MAXY
  866.         ENDIF
  867.         IORIX = IORI
  868.         IX = INT((X-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+1.5)
  869.         IY = INT((Y-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  870.       ELSE
  871.         IF(INOUT.EQ.0) THEN
  872.           IMINX = INT((XMIN-XMINA)/(XMAXA-XMINA)*FLOAT(MAXY-1)+0.5)
  873.           IMAXX = INT((XMAX-XMINA)/(XMAXA-XMINA)*FLOAT(MAXY-1)+0.5)
  874.           IMINY = INT((YMIN-YMINA)/(YMAXA-YMINA)*FLOAT(MAXX-1)+1.5)
  875.           IMAXY = INT((YMAX-YMINA)/(YMAXA-YMINA)*FLOAT(MAXX-1)+1.5)
  876.         ELSE
  877.           IMINX = 0
  878.           IMAXX = MAXY
  879.           IMINY = 0
  880.           IMAXY = MAXX
  881.         ENDIF
  882.         IORIX = IORI + 1
  883.         IF(IORIX.GT.4) IORIX = 1
  884.         IX = MAXY - INT((Y-YMINA)/(YMAXA-YMINA)*FLOAT(MAXY-1)+0.5)
  885.         IY = INT((X-XMINA)/(XMAXA-XMINA)*FLOAT(MAXX-1)+0.5)
  886.       ENDIF
  887. * Calc offset for justification
  888.       IF(JUSTIF.LT.0) IJUST = 0
  889.       IF(JUSTIF.EQ.0) IJUST = (LENG(STRNG)-1)*3
  890.       IF(JUSTIF.GT.0) IJUST = (LENG(STRNG)-1)*6
  891.       DO 60 I=1, LENG(STRNG)
  892. * Calc bottom left of this character
  893.         GOTO(10,20,30,40) IORIX
  894.   10    IC = IX + (I*6-9-IJUST)*ISIZE
  895.         IR = IY - 6*ISIZE
  896.         GOTO 50
  897.   20    IC = IX + 6*ISIZE
  898.         IR = IY + (I*6-9-IJUST)*ISIZE
  899.         GOTO 50
  900.   30    IC = IX + (9-I*6+IJUST)*ISIZE
  901.         IR = IY + 6*ISIZE
  902.         GOTO 50
  903.   40    IC = IX - 6*ISIZE
  904.         IR = IY + (9-I*6+IJUST)*ISIZE
  905. * Plot the character
  906.   50    IF(ISIZE.GT.1) THEN
  907.           DO 200 J=1, 10
  908.             DO 210 K=0, 6
  909.               IDOTS(J,K) = 0
  910.  210        CONTINUE
  911.  200      CONTINUE
  912.         ENDIF
  913.         CH = STRNG(I:I)
  914.         ICH = ICHAR(CH)
  915.         DO 70 J=1, 5
  916.           DO 80 K=1, 9
  917.             NI = (J*9+K+5)/15
  918.             NB = J*9+K+6-15*NI
  919.             IF(MOD(CHARS(NI,ICH),MASK2(NB+1)).GE.MASK2(NB)) THEN
  920.               CALL CHRDOT(IORIX,IC,IR,J*ISIZE,K*ISIZE,IMINX,IMAXX,
  921.      $                    IMINY,IMAXY,IGRAPH)
  922.               IDOTS(K,J) = 1
  923.             ENDIF
  924.   80      CONTINUE
  925.   70    CONTINUE
  926.         IF(ISIZE.GT.1) THEN
  927.           DO 320 ISZ=1, ISIZE-1
  928.             DO 300 J=1, 5
  929.               DO 310 K=1, 9
  930.                 JJ = ISIZE*J
  931.                 KK = ISIZE*K
  932.                 IICH = 0
  933.                 IF(ICH.EQ.3.OR.ICH.EQ.5.OR.ICH.EQ.7.OR.ICH.EQ.12) IICH=1
  934.                 IF (IDOTS(K,J).EQ.1) THEN
  935.                   IF(IDOTS(K,J+1).EQ.1) CALL CHRDOT(IORIX,IC,IR,JJ+ISZ,
  936.      $             KK,IMINX,IMAXX,IMINY,IMAXY,IGRAPH)
  937.                   IF(IDOTS(K+1,J).EQ.1) THEN
  938.                     CALL CHRDOT(IORIX,IC,IR,JJ,KK+ISZ,IMINX,IMAXX,
  939.      $                          IMINY,IMAXY,IGRAPH)
  940.                   ELSE
  941.                     IF(IDOTS(K,J+1).NE.1.AND.IDOTS(K+1,J+1).EQ.1) CALL
  942.      $               CHRDOT(IORIX,IC,IR,JJ+ISZ,KK+ISZ,IMINX,IMAXX,
  943.      $                      IMINY,IMAXY,IGRAPH)
  944.                     IF(IDOTS(K,J-1).NE.1.AND.IDOTS(K+1,J-1).EQ.1) CALL
  945.      $               CHRDOT(IORIX,IC,IR,JJ-ISZ,KK+ISZ,IMINX,IMAXX,
  946.      $                      IMINY,IMAXY,IGRAPH)
  947.                   ENDIF
  948.                   IF(IICH.EQ.1) THEN
  949.                     IF(IDOTS(K+1,J+1).EQ.1) CALL CHRDOT(IORIX,IC,IR,
  950.      $           JJ+ISZ,KK+ISZ,IMINX,IMAXX,IMINY,IMAXY,IGRAPH)
  951.                     IF(IDOTS(K+1,J-1).EQ.1) CALL CHRDOT(IORIX,IC,IR,
  952.      $           JJ-ISZ,KK+ISZ,IMINX,IMAXX,IMINY,IMAXY,IGRAPH)
  953.                   ENDIF
  954.                 ENDIF
  955.  310          CONTINUE
  956.  300        CONTINUE
  957.  320      CONTINUE
  958.         ENDIF
  959.   60  CONTINUE
  960.       RETURN
  961.       END
  962.  
  963. *-----------------------------------------------------------------------
  964.  
  965.       SUBROUTINE LINE(LTYP,X1,Y1,X2,Y2,IGRAPH,NPP,IFPBL,INOUT)
  966. *
  967. * Plot a line from (X1,Y1) to (X2,Y2) on IGRAPH.
  968. * Calls POINT to plot the individual points.
  969. *
  970. * LTYP  = Line type : 1 =  continuous line
  971. *                     2 =  .................
  972. *                     3 =  . . . . . . . . .
  973. *                     4 =  - - - - - - - - -
  974. *                     5 =  -- . -- . -- . --
  975. *
  976. * IGRAPH= The graph memory array
  977. * NPP   = the number of points plotted. Used for the line type patterns.
  978. * IFPBL = 0 to print both end-points of the line,
  979. *         else blank first end-point (for plotting chains of lines)
  980. * INOUT = Border restriction. 0=plot only inside axes, 1=anywhere on graph
  981. *
  982. * DOT(ijk) = Array of patterns for dotted lines
  983. *            i=0 or 1 for dot or no dot, j=LTYP, k=LOHI
  984. *
  985.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  986.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  987.       INTEGER*2 IGRAPH
  988.       DIMENSION IGRAPH(MMAXX,MMAXY), DOT(12,5,2)
  989.       DATA DOT/1,1,1,1,1,1,1,1,1,1,1,1,
  990.      $         1,0,1,0,1,0,1,0,1,0,1,0,
  991.      $         1,0,0,1,0,0,1,0,0,1,0,0,
  992.      $         1,1,1,1,0,0,1,1,1,1,0,0,
  993.      $         1,1,1,0,1,0,1,1,1,0,1,0,
  994.      $         1,1,1,1,1,1,1,1,1,1,1,1,
  995.      $         1,0,0,1,0,0,1,0,0,1,0,0,
  996.      $         1,0,0,0,0,0,1,0,0,0,0,0,
  997.      $         1,1,1,1,1,1,1,1,0,0,0,0,
  998.      $         1,1,1,1,1,1,1,0,0,1,0,0/
  999.       IF(NPP.LT.1) NPP = 1
  1000.       IF(LTYP.LT.0.OR.LTYP.GT.5) LTYP = 1
  1001. * Calc min. no. of points for an unbroken line
  1002.       PNTS = ABS((X2-X1)/(XMAXA-XMINA)*FLOAT(MAXX))
  1003.       PNTS = AMAX1(1.,PNTS,ABS((Y2-Y1)/(YMAXA-YMINA)*FLOAT(MAXY)))
  1004.       IPNTS = INT(PNTS+0.5)
  1005.       DX = (X2-X1)/PNTS
  1006.       DY = (Y2-Y1)/PNTS
  1007.       ISTART = 1
  1008.       X = X1
  1009.       Y = Y1
  1010.       IF(IFPBL.EQ.0) THEN
  1011.         ISTART = 0
  1012.         X = X-DX
  1013.         Y = Y-DY
  1014.       ENDIF
  1015.       DO 10 I=ISTART, IPNTS
  1016.         IF(NPP.GT.12) NPP = 1
  1017.         X = X + DX
  1018.         Y = Y + DY
  1019.         IF(DOT(NPP,LTYP,LOHI).EQ.1) CALL POINT(X,Y,IGRAPH,INOUT)
  1020.         NPP = NPP + 1
  1021.   10  CONTINUE
  1022.       RETURN
  1023.       END
  1024.  
  1025. *-----------------------------------------------------------------------
  1026.  
  1027.       SUBROUTINE SORT(NPTS,X,Y)
  1028. *
  1029. * Sort the data arrays X and Y into ascending order (of X values)
  1030. * NPTS = the number of values to be sorted.
  1031. *
  1032.       DIMENSION X(*),Y(*)
  1033.       M = NPTS
  1034.       L = M/2 + 1
  1035.   10  IF(L.GT.1) THEN
  1036.         L = L - 1
  1037.         XX = X(L)
  1038.         YY = Y(L)
  1039.       ELSE
  1040.         XX = X(M)
  1041.         YY = Y(M)
  1042.         X(M) = X(1)
  1043.         Y(M) = Y(1)
  1044.         M = M - 1
  1045.         IF(M.EQ.1) GOTO 30
  1046.       ENDIF
  1047.       I = L
  1048.       J = 2*L
  1049.       IF(J.LE.M) THEN
  1050.   20    IF(J.LT.M.AND.X(J).LT.X(J+1)) J = J+1
  1051.         IF(XX.LT.X(J)) THEN
  1052.           X(I) = X(J)
  1053.           Y(I) = Y(J)
  1054.           I = J
  1055.           J = 2*J
  1056.         ELSE
  1057.           J = M + 1
  1058.         ENDIF
  1059.         IF(J.LE.M) GO TO 20
  1060.       ENDIF
  1061.       X(I) = XX
  1062.       Y(I) = YY
  1063.       GO TO 10
  1064.   30  X(1) = XX
  1065.       Y(1) = YY
  1066.       RETURN
  1067.       END
  1068.  
  1069. *-----------------------------------------------------------------------
  1070.  
  1071.       SUBROUTINE SPLINE(NPIN,NPOUT,X,Y,XX,YY)
  1072. *
  1073. * Fit a cubic spline to the NPIN (X,Y) pairs, and return NPOUT evenly
  1074. * spaced fitted (XX,YY) data pairs. Also returns sorted (X,Y).
  1075. *
  1076.       DIMENSION X(*), Y(*), XX(*), YY(*), S(500), C(500)
  1077.       CALL SORT(NPIN,X,Y)
  1078.       AI = X(2)-X(1)
  1079.       PI = (Y(2)-Y(1))/AI 
  1080.       S(1) = -1 
  1081.       C(1) = 0
  1082.       DI = -AI 
  1083.       CI = 0
  1084.       DO 10 I=2,NPIN-1
  1085.         A1 = X(I+1)-X(I) 
  1086.         Z = 2*(A1+AI)-DI
  1087.         P2 = (Y(I+1)-Y(I))/A1
  1088.         C(I) = (6*(P2-PI)-CI)/Z
  1089.         CI = C(I)*A1 
  1090.         PI = P2
  1091.         S(I) = A1/Z
  1092.         DI = S(I)*A1 
  1093.         AI = A1
  1094.   10  CONTINUE
  1095.       S(NPIN) = C(NPIN-1)/(1+S(NPIN-1))
  1096.       J = NPIN
  1097.       DO 20 I=1,NPIN-1
  1098.         J = J-1
  1099.         S(J) = C(J)-S(J)*S(J+1)
  1100.   20  CONTINUE
  1101.       IF(NPOUT.GT.500) NPOUT = 500
  1102.       DX = (X(NPIN)-X(1))/(NPOUT-1)
  1103.       XX(1) = X(1) 
  1104.       YY(1) = Y(1) 
  1105.       J = 1
  1106.       DO 30 I=1,NPIN-1 
  1107.         IF(XX(J)+DX.LT.X(I+1)) THEN
  1108.   40      J = J+1
  1109.           XX(J) = XX(J-1)+DX
  1110.           XV = XX(J)-X(I) 
  1111.           T = 2*S(I)+XV*(S(I)-S(I+1))/(X(I)-X(I+1))+S(I+1)
  1112.           YY(J)=Y(I)+XV*((Y(I)-Y(I+1))/(X(I)-X(I+1))+(XX(J)-X(I+1))*T/6)
  1113.           IF(XX(J)+DX.LT.X(I+1)) GOTO 40
  1114.         ENDIF
  1115.   30  CONTINUE
  1116.       XX(NPOUT) = X(NPIN)
  1117.       YY(NPOUT) = Y(NPIN)
  1118.       RETURN
  1119.       END
  1120.  
  1121. *-----------------------------------------------------------------------
  1122.  
  1123.       SUBROUTINE POINTS(IPT,ISIZE,LTYP,NPTS,X,Y,IGRAPH,INOUT)
  1124. *
  1125. * Plot an array of points [X(i),Y(i)] on IGRAPH
  1126. *
  1127. * IPT   = Symbol to be plotted at each point
  1128. *         (1 = dot, 2..8 = symbol, 32..126 = ASCII character)
  1129. * ISIZE = Size of mark (1..n) Try 2 or 3 for a start.
  1130. * LTYP  = Line type for joining points.
  1131. *         0 = no line,
  1132. *         1 to 5 straight lines,
  1133. *         -5 to -1 for cubic spline fit (smooth curve).
  1134. * NPTS  = No of points to be plotted
  1135. * X,Y   = the array of points
  1136. * IGRAPH= The graph memory array
  1137. * INOUT = Border restriction. 0=plot only inside axes, 1=anywhere on graph
  1138. *
  1139.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  1140.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  1141.       INTEGER*2 IGRAPH
  1142.       DIMENSION X(*), Y(*), IGRAPH(MMAXX,MMAXY), XX(500), YY(500)
  1143.       DO 10 I=1, NPTS
  1144.         CALL MARKPT(IPT,ISIZE,X(I),Y(I),IGRAPH,INOUT)
  1145.   10  CONTINUE
  1146.       NPP = 1
  1147.       IF(LTYP.GT.0) THEN
  1148.         DO 20 I=2,NPTS
  1149.           CALL LINE(LTYP,X(I-1),Y(I-1),X(I),Y(I),IGRAPH,NPP,1,INOUT)
  1150.   20    CONTINUE
  1151.       ELSEIF(LTYP.LT.0) THEN
  1152. *       Spline fit
  1153. *------ First sort into ascending x values, then calc and plot the spline
  1154.         NP = INT(ABS((X(NPTS)-X(1))/(XMAXA-XMINA)*(MAXX-1)/5.))
  1155.         CALL SPLINE(NPTS,NP,X,Y,XX,YY)
  1156.         DO 30 I=2, NP
  1157.         CALL LINE(-LTYP,XX(I-1),YY(I-1),XX(I),YY(I),IGRAPH,NPP,1,INOUT)
  1158.   30    CONTINUE
  1159.       ENDIF         
  1160.       RETURN
  1161.       END
  1162.  
  1163. *-----------------------------------------------------------------------
  1164.  
  1165.       SUBROUTINE FUNCT(IFN,P,LTYP,X1,X2,IGRAPH,INOUT)
  1166. *
  1167. * Plot a continuous function from X1 to X2 on IGRAPH
  1168. *
  1169. * IFN   = Function number in subroutine GRAPHFNS
  1170. * P     = The array of parameters to be passed to function IFN.
  1171. * LTYP  = Line type for plotting the function.
  1172. *         0 = no line, 1 to 5 = solid, dotted etc..
  1173. * IGRAPH= The graph memory array
  1174. * INOUT = Border restriction. 0=plot only inside axes, 1=anywhere on graph
  1175. *
  1176.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  1177.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  1178.       INTEGER*2 IGRAPH
  1179.       DIMENSION IGRAPH(MMAXX,MMAXY), P(*)
  1180.       IPNTS = INT(ABS((X2-X1)/(XMAXA-XMINA)*(MAXX-1)/4.))
  1181.       IF(IPNTS.LT.1) IPNTS = 1
  1182.       XB = X1
  1183. * Take logs as necessary if log scales specified
  1184.       IF(LOGX.GT.0) YB = FGRAPH(IFN,P,X1)
  1185.       IF(LOGX.EQ.0) YB = FGRAPH(IFN,P,10.**X1)
  1186.       IF(LOGY.EQ.0) YB = ALOG10(YB)
  1187.       DX = (X2-X1)/FLOAT(IPNTS)
  1188.       NPP = 1
  1189.       DO 10 I=1, IPNTS
  1190.         XA = XB
  1191.         YA = YB
  1192.         XB = X1 + I*DX
  1193.         IF(LOGX.GT.0) YB = FGRAPH(IFN,P,XB)
  1194.         IF(LOGX.EQ.0) YB = FGRAPH(IFN,P,10.**XB)
  1195.         IF(LOGY.EQ.0) YB = ALOG10(YB)
  1196.         CALL LINE(LTYP,XA,YA,XB,YB,IGRAPH,NPP,1,INOUT)
  1197.   10  CONTINUE
  1198.       RETURN
  1199.       END
  1200.  
  1201. *-----------------------------------------------------------------------
  1202.  
  1203.       SUBROUTINE CLRGRF(IGRAPH)
  1204. *
  1205. * Set IGRAPH to zero - ie clear the graph
  1206. *
  1207.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  1208.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  1209.       INTEGER*2 IGRAPH
  1210.       DIMENSION IGRAPH(MMAXX,MMAXY)
  1211.       DO 10 ICOL=1, MMAXX
  1212.         DO 20 IROW=1, MMAXY
  1213.           IGRAPH(ICOL,IROW) = 0
  1214.   20    CONTINUE
  1215.   10  CONTINUE
  1216.       RETURN
  1217.       END
  1218.  
  1219. *-----------------------------------------------------------------------
  1220.  
  1221.       SUBROUTINE CHRDOT(IORIX,IC,IR,J,K,IMINX,IMAXX,IMINY,IMAXY,
  1222.      $                  IGRAPH)
  1223. *
  1224. * For internal use by subroutine TEXT.
  1225. * Set this dot to on (for plotting characters).
  1226. * IC,IR = Col, row for bottom left of character
  1227. * J,K   = Offset in dots to current dot position
  1228. * IMINX..IMAXY = Integer limits of plotting area
  1229. *
  1230.       COMMON /GRF/XMINA,XMAXA,YMINA,YMAXA,XMIN,YMIN,XMAX,YMAX,MAXX,
  1231.      $            MAXY,MMAXX,MMAXY,LOHI,IVH,LOGX,LOGY,DPIV,DPIH
  1232.       INTEGER*2 IGRAPH
  1233.       DIMENSION IGRAPH(MMAXX,MMAXY), MASKHI(14)
  1234.       DATA MASKHI/1,8,2,9,3,10,4,11,5,12,6,13,7,14/
  1235.       GOTO(110,120,130,140) IORIX
  1236.  110  ICOL = IC + J
  1237.       IROW = IR + K
  1238.       GOTO 150
  1239.  120  ICOL = IC - K
  1240.       IROW = IR + J
  1241.       GOTO 150
  1242.  130  ICOL = IC - J
  1243.       IROW = IR - K
  1244.       GOTO 150
  1245.  140  ICOL = IC + K
  1246.       IROW = IR - J
  1247.  150  IF(ICOL.GT.IMINX.AND.ICOL.LT.IMAXX.AND.IROW.GT.IMINY.AND.IROW.
  1248.      $ LT.IMAXY) THEN
  1249.         IRR = IROW/14+1
  1250.         IBIT = IRR*14-IROW
  1251.         IF(LOHI.EQ.2) IBIT = MASKHI(IBIT)
  1252.         CALL SETBIT(IGRAPH(ICOL,IRR),IBIT)
  1253.       ENDIF
  1254.       RETURN
  1255.       END
  1256.  
  1257. *-----------------------------------------------------------------------
  1258.  
  1259.       FUNCTION LENG(STRING)
  1260. *
  1261. * Returns the length of STRING, excluding trailing blanks
  1262. *
  1263.       CHARACTER*80 STRING
  1264.       I = LEN(STRING)
  1265.       IF(I.LE.1) GOTO 20
  1266.   10  I = I - 1
  1267.       IF(STRING(I:I).EQ.' '.AND.I.GT.1) GOTO 10
  1268.   20  LENG = I
  1269.       RETURN
  1270.       END
  1271.  
  1272. *-----------------------------------------------------------------------
  1273.